/*
 * @Description:
 * @Version:
 * @Author: Troubadour
 * @Date: 2022-08-13 19:20:15
 * @LastEditors: Troubadour
 * @LastEditTime: 2022-09-12 10:48:15
 */

#include "myiic.h"

/*----------------------------------------Private----------------------------------------*/
#if 1
/**
 * @function: IIC_Delay
 * @brief IIC延迟函数
 * @param {*}
 * @return {*}
 */
static void delay_xus(__IO uint32_t nTime)
{
	unsigned char i;
	for(i=0; i>5; i++);
	//	条件为主时钟频率为72M, MDK优化等级为1
	//  循环为10时，SCL的频率为 205KHZ
	//	循环为7时，SCL的频率为 347KHZ，SCL高电平时间1.5us，SCL低电平时间2.87us
	//	循环为5时，SCL的频率为 421KHZ，SCL高电平时间1.25us，SCL低电平时间2.37us
}

#else
/**
 * @function: delay_xus
 * @brief 提供us延时
 * @param {__IO uint32_t} nTime：延时us时间
 * @return {*}
 */
static void delay_xus(__IO uint32_t nTime)
{
    int old_val, new_val, val;

    if (nTime > 900)
    {
        for (old_val = 0; old_val < nTime / 900; old_val++)
        {
            delay_xus(900);
        }
        nTime = nTime % 900;
    }

    old_val = SysTick->VAL;
    new_val = old_val - CPU_FREQUENCY_MHZ * nTime;
    if (new_val >= 0)
    {
        do
        {
            val = SysTick->VAL;
        } while ((val < old_val) && (val >= new_val));
    }
    else
    {
        new_val += CPU_FREQUENCY_MHZ * 1000;
        do
        {
            val = SysTick->VAL;
        } while ((val <= old_val) || (val > new_val));
    }
}
#endif


/**
 * @function: SDA_Output
 * @brief 设置SDA为输出模式
 * @param {*}
 * @return {*}
 */
static void SDA_Output(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = MYIIC_SDA_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(MYIIC_SDA_PORT, &GPIO_InitStruct);
}

/**
 * @function: SDA_Input
 * @brief 设置SDA为输入模式
 * @param {*}
 * @return {*}
 */
static void SDA_Input(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = MYIIC_SDA_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(MYIIC_SDA_PORT, &GPIO_InitStruct);
}

/**
 * @function: SCL_Output
 * @brief 设置SCL为输出模式
 * @param {*}
 * @return {*}
 */
static void SCL_Output(void)
{
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.Pin = MYIIC_SCL_PIN;
    GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;
    HAL_GPIO_Init(MYIIC_SCL_PORT, &GPIO_InitStruct);
}

/**
 * @function: SCL_Input
 * @brief 设置SCL为输入模式
 * @param {*}
 * @return {*}
 */
// static void SCL_Input(void)
// {
//     GPIO_InitTypeDef GPIO_InitStruct;
//     GPIO_InitStruct.Pin = MYIIC_SCL_PIN;
//     GPIO_InitStruct.Mode = GPIO_MODE_INPUT;
//     GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
//     HAL_GPIO_Init(MYIIC_SCL_PORT, &GPIO_InitStruct);
// }

/*----------------------------------------Globle----------------------------------------*/
/**
 * @function: IIC_Init
 * @brief IIC初始化
 * @param {*}
 * @return {*}
 */
void IIC_Init(void)
{
    SCL_Output();
    SDA_Output();
    SCL_Dout_HIGH();
    SDA_Dout_HIGH();
}

/**
 * @function: IIC_Start
 * @brief 产生IIC启动信号
 * @param {*}
 * @return {*}
 */
void IIC_Start(void)
{
    SDA_Output();
    SDA_Dout_HIGH();
    SCL_Dout_HIGH();
    Delay_us(4);
    SDA_Dout_LOW();
    Delay_us(4);
    SCL_Dout_LOW();
}

/**
 * @function: IIC_Start
 * @brief 产生IIC停止信号
 * @param {*}
 * @return {*}
 */
void IIC_Stop(void)
{
    SDA_Output();
    SCL_Dout_LOW();
    SDA_Dout_LOW();
    Delay_us(4);
    SCL_Dout_HIGH();
    SDA_Dout_HIGH();
    Delay_us(4);
}

/**
 * @function: IIC_Wait_Ack
 * @brief 等待ACK应答
 * @param {*}
 * @return {HAL_StatusTypeDef} HAL_OK：有应答；HAL_ERROR：超时，无应答
 */
HAL_StatusTypeDef IIC_Wait_Ack(void)
{
    uint8_t ucErrTime = 0;
    SDA_Input();
    SDA_Dout_HIGH();
    Delay_us(1);
    SCL_Dout_HIGH();
    Delay_us(1);
    while (SDA_Data_IN())
    {
        ucErrTime++;
        if (ucErrTime > 250)
        {
            IIC_Stop();
            return HAL_ERROR;
        }
    }
    SCL_Dout_LOW(); //时钟输出0
    return HAL_OK;
}

/**
 * @function: IIC_Ack
 * @brief 产生ACK应答
 * @param {*}
 * @return {*}
 */
void IIC_Ack(void)
{
    SCL_Dout_LOW();
    SDA_Output();
    SDA_Dout_LOW();
    Delay_us(2);
    SCL_Dout_HIGH();
    Delay_us(2);
    SCL_Dout_LOW();
}

/**
 * @function: IIC_NAck
 * @brief 不产生ACK应答
 * @param {*}
 * @return {*}
 */
void IIC_NAck(void)
{
    SCL_Dout_LOW();
    SDA_Output();
    SDA_Dout_HIGH();
    Delay_us(2);
    SCL_Dout_HIGH();
    Delay_us(2);
    SCL_Dout_LOW();
}

/**
 * @function:IIC_Send_Byte
 * @brief IIC发送一个字节
 * @param {uint8_t} txd：要发送的数据
 * @return {*}
 */
void IIC_Send_Byte(uint8_t txd)
{
    uint8_t t;
    //拉低时钟开始数据传输
    SDA_Output();
    SCL_Dout_LOW();
    for (t = 0; t < 8; t++)
    {
        SDA_Write((txd & 0x80) >> 7);
        txd <<= 1;
        Delay_us(5);    //对TEA5767这三个延时都是必须的
        SCL_Dout_HIGH();
        Delay_us(5);
        SCL_Dout_LOW();
        // Delay_us(2);
    }
}

/**
 * @function: IIC_Read_Byte
 * @brief 读1个字节
 * @param {uint8_t} ack：ack=1时，发送ACK；ack=0，发送No ACK
 * @return {uint8_t} receive：返回读到的1个字节
 */
uint8_t IIC_Read_Byte(uint8_t ack)
{
    unsigned char i, receive = 0;
    // SDA设置为输入
    SDA_Input();
    for (i = 0; i < 8; i++)
    {
        SCL_Dout_LOW();
        Delay_us(5);
        SCL_Dout_HIGH();
        receive <<= 1;
        if (SDA_Data_IN())
            receive++;
        Delay_us(5);
    }
    if (!ack)
        IIC_NAck(); //发送nACK
    else
        IIC_Ack(); //发送ACK

    return receive;
}
